﻿using SQLitePCL;
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using Windows.Storage;
using Windows.Storage.Streams;
using Windows.UI.Popups;
using System.Linq;
using System.Threading.Tasks;
using Windows.UI.Xaml.Media;
using Windows.ApplicationModel;
using System.Collections.ObjectModel;
using Windows.UI;

namespace Ganjine.DataModel
{
    public class FontItem
    {
        public string Name { get; set; }
        public FontFamily Font { get; set; }
        public FontItem(string name, FontFamily font)
        {
            Name = name;
            Font = font;
        }
    }

    public class PoetItem
    {
        public string ImagePath { get; set; }
        public string PoetName { get; set; }
        public int PoetID { get; set; }
        public int CatID { get; set; }
        public int OrderID { get; set; }
        public Brush BackColor { get; set; }
        public Windows.UI.Xaml.Visibility ImageVisibility { get; set; }
        public override string ToString()
        {
            return PoetName;
        }
        public PoetItem()
        {
            ImageVisibility = Windows.UI.Xaml.Visibility.Visible;
        }
    }

    public enum PoemItemType
    {
        Category = 1,
        Poem = 2
    }

    public class PoemItem
    {
        public string Text { get; set; }
        public string PoetName { get; set; }
        public PoemItemType Type { get; set; }
        public int ID { get; set; }
        public string s1 { get; set; }
        public string s2 { get; set; }
        public bool HasAdditionalData { get; set; }
        public int OrderID { get; set; }
    }

    public class DataBridge1
    {
        public string title { get; set; }
        public int id { get; set; }
        public int poetid { get; set; }
        public string rootPath { get; set; }
        public bool isChildItem { get; set; }
    }

    public class DataBridge2
    {
        public int id { get; set; }
        public int parentid { get; set; }
        public string title { get; set; }
        public bool HideNextPrevKeys { get; set; }
    }

    public class DataBridgeSearch
    {
        public string term { get; set; }
        public int sourceId { get; set; }

        public DataBridgeSearch(string _term, int _sourceId = -1)
        {
            term = _term;
            sourceId = _sourceId;
        }
    }

    public class VerseItem
    {
        public string hemistich1 { get; set; }
        public string hemistich2 { get; set; }
        public Windows.UI.Xaml.Visibility hemistich2Visibility { get; set; }
        public Windows.UI.Xaml.Media.Brush ForegroundColor1 { get; set; }
        public Windows.UI.Xaml.Media.Brush ForegroundColor2 { get; set; }
        public FontFamily font { get; set; }
        public double fontSize { get; set; }
        public int lineHeight { get; set; }
    }

    public class VerseItem2
    {
        public string text { get; set; }
        public int position { get; set; }
    }

    public class DataSource
    {

        string[] Colors = { "#FFF3B200", "#FF77B900", "#FF2572EB", "#FFAD103C", "#FF632F00", "#FFB01E00", "#FFC1004F", "#FF7200AC", "#FF4617B4", "#FF006AC1", "#FF008287", "#FF199900", "#FF00C13F", "#FFFF981D", "#FFFF2E12", "#FFFF1D77", "#FFAA40FF", "#FF1FAEFF", "#FF56C5FF", "#FF00D8CC", "#FF91D100", "#FFE1B700", "#FFFF76BC", "#FF00A3A3", "#FFFE7C22" };


        public ObservableCollection<PoetItem> GetListOfPoets()
        {
            ObservableCollection<PoetItem> poets = new ObservableCollection<PoetItem>();
            CheckDBConnection();
            using (var statement = App.conn.Prepare("SELECT id, name, cat_id FROM poet"))
            {
                Random r = new Random(0); //Constant seed, because we want the colors to be always the same for each poet.
                while (statement.Step() == SQLiteResult.ROW)
                {
                    PoetItem pi = new PoetItem()
                    {
                        PoetID = int.Parse(statement[0].ToString()),
                        PoetName = statement[1].ToString(),
                        CatID = int.Parse(statement[2].ToString()),
                        ImagePath = "Assets/" + statement[0].ToString() + ".jpg",
                        BackColor = new SolidColorBrush(ColorFromString(Colors[r.Next(Colors.Count())])),
                    };
                    poets.Add(pi);
                }
            }
            return poets;
        }

        /// <summary>
        /// Convert a Hex color string to a Color object
        /// </summary>
        /// <param name="htmlColor">Color string in #rgb, #argb, #rrggbb or #aarrggbb format</param>
        /// <returns>A color object</returns>
        public static Color ColorFromString(string htmlColor)
        {
            htmlColor = htmlColor.Replace("#", "");
            byte a = 0xff, r = 0, g = 0, b = 0;
            switch (htmlColor.Length)
            {
                case 3:
                    r = byte.Parse(htmlColor.Substring(0, 1), System.Globalization.NumberStyles.HexNumber);
                    g = byte.Parse(htmlColor.Substring(1, 1), System.Globalization.NumberStyles.HexNumber);
                    b = byte.Parse(htmlColor.Substring(2, 1), System.Globalization.NumberStyles.HexNumber);
                    break;
                case 4:
                    a = byte.Parse(htmlColor.Substring(0, 1), System.Globalization.NumberStyles.HexNumber);
                    r = byte.Parse(htmlColor.Substring(1, 1), System.Globalization.NumberStyles.HexNumber);
                    g = byte.Parse(htmlColor.Substring(2, 1), System.Globalization.NumberStyles.HexNumber);
                    b = byte.Parse(htmlColor.Substring(3, 1), System.Globalization.NumberStyles.HexNumber);
                    break;
                case 6:
                    r = byte.Parse(htmlColor.Substring(0, 2), System.Globalization.NumberStyles.HexNumber);
                    g = byte.Parse(htmlColor.Substring(2, 2), System.Globalization.NumberStyles.HexNumber);
                    b = byte.Parse(htmlColor.Substring(4, 2), System.Globalization.NumberStyles.HexNumber);
                    break;
                case 8:
                    a = byte.Parse(htmlColor.Substring(0, 2), System.Globalization.NumberStyles.HexNumber);
                    r = byte.Parse(htmlColor.Substring(2, 2), System.Globalization.NumberStyles.HexNumber);
                    g = byte.Parse(htmlColor.Substring(4, 2), System.Globalization.NumberStyles.HexNumber);
                    b = byte.Parse(htmlColor.Substring(6, 2), System.Globalization.NumberStyles.HexNumber);
                    break;
            }
            return Color.FromArgb(a, r, g, b);
        }

        public bool HasChildren(int catid)
        {
            bool b = false;
            CheckDBConnection();
            using (var statement = App.conn.Prepare("SELECT id FROM cat WHERE parent_id=" + catid.ToString()))
            {
                if (statement.Step() == SQLiteResult.ROW)
                {
                    b = true;
                }
            }
            return b;
        }

        public void CheckDBConnection(bool recreate = false)
        {
            if ((App.conn == null) || (recreate))
            {
                App.conn = new SQLiteConnection(Path.Combine(ApplicationData.Current.LocalFolder.Path, "ganjoor2.s3db"));
            }
        }

        public List<PoemItem> GetListOfChildren(int parentid)
        {
            List<PoemItem> p = new List<PoemItem>();
            CheckDBConnection();
            using (var statement = App.conn.Prepare("SELECT id, text FROM cat WHERE parent_id=" + parentid.ToString()))
            {
                while (statement.Step() == SQLiteResult.ROW)
                {
                    PoemItem pi = new PoemItem()
                    {
                        ID = int.Parse(statement[0].ToString()),
                        Text = statement[1].ToString(),
                        Type = PoemItemType.Category,
                        HasAdditionalData = false
                    };
                    p.Add(pi);
                }
            }
            return p;
        }

        public static string Truncate(string value, int maxLength)
        {
            if (string.IsNullOrEmpty(value)) return value;
            return value.Length <= maxLength ? value : value.Substring(0, maxLength);
        }

        public List<PoemItem> GetListOfPoems(int catid)
        {
            List<PoemItem> p = new List<PoemItem>();
            CheckDBConnection();
            using (var statement = App.conn.Prepare("SELECT id, title, (SELECT text FROM verse WHERE poem_id=id LIMIT 1), (SELECT text FROM verse WHERE poem_id=id LIMIT 1,1) FROM poem WHERE cat_id=" + catid.ToString()))
            {
                while (statement.Step() == SQLiteResult.ROW)
                {
                    PoemItem pi = new PoemItem()
                    {
                        ID = int.Parse(statement[0].ToString()),
                        Text = statement[1].ToString(),
                        Type = PoemItemType.Poem,
                        s1 = (statement[2] == null ? "" : Truncate(statement[2].ToString(), 200)),
                        HasAdditionalData = true
                    };

                    if (statement[3] != null)
                    {
                        pi.s2 = Truncate(statement[3].ToString(), 200);
                    }


                    p.Add(pi);
                }
            }
            return p;
        }

        public List<VerseItem> GetVerses(int poemID)
        {
            List<VerseItem> p = new List<VerseItem>();
            List<int> vorders = new List<int>();
            CheckDBConnection(true);
            using (var statement = App.conn.Prepare("SELECT text, position, vorder FROM verse WHERE poem_id=" + poemID.ToString()))
            {
                while (statement.Step() == SQLiteResult.ROW)
                {
                    /* To resolve a bug which happens in poem_id=50255, most probably an SQLite for Windows Phone bug. */
                    int vorder = int.Parse(statement[2].ToString());
                    if (vorders.Contains(vorder))
                        break;
                    vorders.Add(vorder);
                    /***/

                    VerseItem s = new VerseItem();

                    s.hemistich1 = statement[0].ToString();

                    if ((statement[1].ToString() == "0") || (statement[1].ToString() == "1"))
                    {
                        s.hemistich2Visibility = Windows.UI.Xaml.Visibility.Visible;
                        //second Hemistich (مصراع)
                        if (statement.Step() == SQLiteResult.ROW)
                        {
                            s.hemistich2 = statement[0].ToString();
                        }
                        else
                        {
                            //A Verse didn't have second Hemistich. So We'll ignore it.
                            s.hemistich2 = "";
                            s.hemistich2Visibility = Windows.UI.Xaml.Visibility.Collapsed;
                        }
                    }
                    else
                    {
                        s.hemistich2 = "";
                        s.hemistich2Visibility = Windows.UI.Xaml.Visibility.Collapsed;
                    }
                    p.Add(s);
                }
            }
            return p;
        }

        public List<VerseItem2> GetVerses2(int poemID)
        {
            List<VerseItem2> p = new List<VerseItem2>();
            CheckDBConnection();
            using (var statement = App.conn.Prepare("SELECT text, position FROM verse WHERE poem_id=" + poemID.ToString()))
            {
                while (statement.Step() == SQLiteResult.ROW)
                {
                    VerseItem2 s = new VerseItem2();
                    s.text = statement[0].ToString();
                    s.position = int.Parse(statement[1].ToString());
                    p.Add(s);
                }
            }
            return p;
        }

        public string getPoetNameOfAPoem(int poemid)
        {
            string s = "";
            CheckDBConnection();
            using (var statement = App.conn.Prepare("SELECT name FROM poet WHERE id  = (SELECT poet_id FROM cat WHERE id=(SELECT cat_id FROM poem WHERE id=" + poemid.ToString() + "))"))
            {
                if (statement.Step() == SQLiteResult.ROW)
                {
                    s = statement[0].ToString();
                }
            }
            return s;
        }

        public List<PoemItem> Search(string s, int poetid)
        {
            List<PoemItem> p = new List<PoemItem>();
            string extraCommand = "";
            string LimitCommand = "";
            if (poetid > 0)
            {
                extraCommand = " AND poem_id IN (SELECT id FROM poem WHERE cat_id IN (SELECT id FROM cat WHERE poet_id = " + poetid + "))";
            }

            //We'll show 1000 results at most. Who is gonna scroll through so much entries?! :)
            CheckDBConnection();
            using (var statement = App.conn.Prepare("SELECT text,(SELECT id FROM poem WHERE id=poem_id), (SELECT title FROM poem WHERE id=poem_id), (SELECT name FROM poet WHERE id  = (SELECT poet_id FROM cat WHERE id=(SELECT cat_id FROM poem WHERE id=poem_id))) FROM verse WHERE text LIKE '%" + s + "%' " + extraCommand + LimitCommand))
            {
                while (statement.Step() == SQLiteResult.ROW)
                {
                    PoemItem p1 = new PoemItem()
                    {
                        s1 = statement[0].ToString(),
                        ID = int.Parse(statement[1].ToString()),
                        Text = statement[3].ToString() + ": " + statement[2].ToString(),
                        Type = PoemItemType.Poem,
                        HasAdditionalData = true
                    };
                    p.Add(p1);

                }
            }
            return p;
        }

        public async Task InitializeSettings()
        {
            StorageFile storageFile;
            try
            {
                storageFile = await ApplicationData.Current.RoamingFolder.GetFileAsync("settings.txt");
                using (Stream stream = (await storageFile.OpenReadAsync()).AsStreamForRead())
                {
                    using (StreamReader sr = new StreamReader(stream))
                    {
                        try
                        {
                            string s1 = sr.ReadLine();
                            //Limit search removed, but we keep reading this line due to backward compatibility.

                            s1 = sr.ReadLine();

                            App.DefaultFont = null;

                            if (s1 == "2")
                                App.DefaultFont = (FontFamily)App.Current.Resources["NazaninFontFamily"];
                            else if (s1 == "3")
                                App.DefaultFont = (FontFamily)App.Current.Resources["KamranFontFamily"];
                            else if (s1 == "4")
                                App.DefaultFont = (FontFamily)App.Current.Resources["NastaliqFontFamily"];
                            else if (s1 == "5")
                                App.DefaultFont = (FontFamily)App.Current.Resources["ArashFontFamily"];
                            else if (s1 == "6")
                                App.DefaultFont = (FontFamily)App.Current.Resources["ArazFontFamily"];
                            else if (s1 == "7")
                                App.DefaultFont = (FontFamily)App.Current.Resources["ArsooFontFamily"];
                            else if (s1 == "8")
                                App.DefaultFont = (FontFamily)App.Current.Resources["DastNevisFontFamily"];
                            else if (s1 == "9")
                                App.DefaultFont = (FontFamily)App.Current.Resources["DomrolFontFamily"];
                            else if (s1 == "10")
                                App.DefaultFont = (FontFamily)App.Current.Resources["KhodkarFontFamily"];
                            else if (s1 == "11")
                                App.DefaultFont = (FontFamily)App.Current.Resources["MitraFontFamily"];
                            else if (s1 == "12")
                                App.DefaultFont = (FontFamily)App.Current.Resources["RoyaFontFamily"];
                            else if (s1 == "13")
                                App.DefaultFont = (FontFamily)App.Current.Resources["ThuluthFontFamily"];
                            else if (s1 == "14")
                                App.DefaultFont = (FontFamily)App.Current.Resources["YekanFontFamily"];
                        }
                        catch
                        {
                            App.DefaultFont = (FontFamily)App.Current.Resources["NazaninFontFamily"];
                            SaveSettings();
                        }
                        try
                        {
                            string s2 = sr.ReadLine();
                            double.TryParse(s2, out App.DefaultFontSize);
                        }
                        catch
                        {

                        }
                    }

                }

                return; //Don't go further
            }
            catch
            {
                //Will create file after catch.
                App.DefaultFont = (FontFamily)App.Current.Resources["NazaninFontFamily"];
                SaveSettings();
            }

        }

        public async Task SaveSettings()
        {
            try
            {
                string s = "";
                s = "0\n";
                // Limit search is removed, but we still write this, for backward compatibility.


                if (App.DefaultFont == null)
                    s += "1\n";
                else
                {
                    string ss = App.DefaultFont.Source.ToString();
                    if (ss.Contains("Nazanin"))
                        s += "2\n";
                    else if (ss.Contains("Kamran"))
                        s += "3\n";
                    else if (ss.Contains("Nastaliq"))
                        s += "4\n";
                    else if (ss.Contains("Arash"))
                        s += "5\n";
                    else if (ss.Contains("Araz"))
                        s += "6\n";
                    else if (ss.Contains("Arsoo"))
                        s += "7\n";
                    else if (ss.Contains("DastNevis"))
                        s += "8\n";
                    else if (ss.Contains("Domrol"))
                        s += "9\n";
                    else if (ss.Contains("Khodkar"))
                        s += "10\n";
                    else if (ss.Contains("Mitra"))
                        s += "11\n";
                    else if (ss.Contains("Roya"))
                        s += "12\n";
                    else if (ss.Contains("Thuluth"))
                        s += "13\n";
                    else if (ss.Contains("Yekan"))
                        s += "14\n";
                }

                s += App.DefaultFontSize + "\n";

                byte[] fileBytes = System.Text.Encoding.UTF8.GetBytes(s.ToCharArray());
                try
                {
                    var sf = await ApplicationData.Current.RoamingFolder.GetFileAsync("settings.txt");
                    await sf.DeleteAsync();
                }
                catch { }
                var storageFile = await ApplicationData.Current.RoamingFolder.CreateFileAsync("settings.txt");

                using (var f = await storageFile.OpenStreamForWriteAsync())
                {
                    f.Write(fileBytes, 0, fileBytes.Length);
                }
            }
            catch
            {
                var dialog = new MessageDialog("خطا در ذخیره تنظیمات.");
                dialog.ShowAsync();
            }
        }

        public async Task InitializeFavorites()
        {
            StorageFile storageFile;
            try
            {
                storageFile = await ApplicationData.Current.RoamingFolder.GetFileAsync("favorites.txt");
                using (Stream stream = (await storageFile.OpenReadAsync()).AsStreamForRead())
                {
                    using (StreamReader sr = new StreamReader(stream))
                    {
                        try
                        {
                            App.favorites.Clear();

                            string s1 = sr.ReadLine();

                            var a = s1.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
                            foreach (string s in a)
                            {
                                App.favorites.Add(GetPoem(int.Parse(s), false));
                            }
                        }
                        catch
                        {
                            int i = 32;
                        }
                    }

                }

                return; //Don't go further
            }
            catch
            {
                //Will create file after catch.
                int i = 33;
            }
            storageFile = await ApplicationData.Current.RoamingFolder.CreateFileAsync("favorites.txt");
        }

        public PoemItem GetPoem(int poemid, bool poetInText = true)
        {
            PoemItem p = new PoemItem();
            CheckDBConnection();
            using (var statement = App.conn.Prepare("SELECT title, (SELECT text FROM verse WHERE poem_id=id LIMIT 1), (SELECT text FROM verse WHERE poem_id=id LIMIT 1,1), (SELECT name FROM poet WHERE id  = (SELECT poet_id FROM cat WHERE id=(SELECT cat_id FROM poem WHERE id=" + poemid.ToString() + "))) FROM poem WHERE id=" + poemid.ToString()))
            {
                if (statement.Step() == SQLiteResult.ROW)
                {
                    p.ID = poemid;
                    if (poetInText)
                        p.Text = statement[3].ToString() + ": " + statement[0].ToString();
                    else
                        p.Text = statement[0].ToString();
                    p.PoetName = statement[3].ToString();
                    p.Type = PoemItemType.Poem;
                    if (statement[1] != null)
                        p.s1 = statement[1].ToString();
                    else
                        p.s1 = "";

                    if (statement[2] != null)
                        p.s2 = statement[2].ToString();
                    else
                        p.s2 = "";

                    p.HasAdditionalData = true;
                }
            }
            return p;
        }

        public async Task SaveFavorites()
        {
            try
            {
                string s = "";
                foreach (PoemItem item in App.favorites)
                {
                    s = item.ID.ToString() + ',' + s; //Add latest favorites to the top.
                }
                byte[] fileBytes = System.Text.Encoding.UTF8.GetBytes(s.ToCharArray());
                try
                {
                    var sf = await ApplicationData.Current.RoamingFolder.GetFileAsync("favorites.txt");
                    await sf.DeleteAsync();
                }
                catch { }
                var storageFile = await ApplicationData.Current.RoamingFolder.CreateFileAsync("favorites.txt");

                using (var f = await storageFile.OpenStreamForWriteAsync())
                {
                    f.Write(fileBytes, 0, fileBytes.Length);
                }
            }
            catch
            {
                var dialog = new MessageDialog("خطا در ذخیره علاقه‌مندی‌ها.");
                dialog.ShowAsync();
            }
        }

        internal async void AddToFavorites(int i)
        {
            PoemItem p = GetPoem(i);
            App.favorites.Add(p);
            await SaveFavorites();
            await InitializeFavorites();
        }

        internal async void RemoveFromFavorites(int i)
        {
            var ptemp = (from PoemItem p in App.favorites
                         where ((p.ID != i) && (p.ID != 0))
                         select p).ToList();
            App.favorites.Clear();
            App.favorites.AddRange(ptemp);
            await App.dataSource.SaveFavorites();
            await App.dataSource.InitializeFavorites();
        }



    }
}
